
//////////////////////////////////////////////////////////////////////////////////	 
//
//  文 件 名   : MatoConfig.c
//  版 本 号   : 1.0
//  作    者   : Wsy
//  生成日期   : 2024/3/13
//  邮箱       : 18269214440@163.com
//  功能描述   : 各种继电器开关函数和相关引脚初始化函数以及各种洗衣模式的配套功能函数
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////


#include "stm32f4xx.h" //必须添加
#include "FreeRTOS.h"
#include "task.h"
#include "delay.h" //用户自行封装的延时函数，用于实现精确的非阻塞延时
#include "mator.h"
#include "sys.h"
#include "oled.h"
#include "Water.h"
#include "stm32f4xx.h"
#include "delay.h"
#include <stdbool.h>
#include <stdio.h>
#include "sys.h"
#include "oled.h"
// #include "bmp.h"
#include "water.h"

// 定义一个全局变量来确认是否已经上锁
/******* 0 空闲  |  1 上锁  *************/
volatile int En_Block = 0;

// 定义一个全局变量来确定是否正在运行
/******* 0 空闲  |  1 工作  *************/
volatile int En_Run = 0;

// 定义一个全局变量来表示剩余时间
volatile char time_arr[20] = {0}; // 定义字符数组存储时间

// 初始化各模式的洗涤时间、漂洗时间、脱水时间、烘干时间

/*******************左边1-8模式*************/
volatile int mode_1[4] = {20, 10, 20, 20}; // 标准洗
volatile int mode_2[4] = {20, 05, 10, 00}; // 快速洗
volatile int mode_3[4] = {30, 10, 20, 20}; // 洗+烘
volatile int mode_4[4] = {20, 20, 10, 00}; // 漂+洗
volatile int mode_5[4] = {00, 00, 20, 20}; // 单烘干
volatile int mode_6[4] = {00, 00, 20, 00}; // 单脱水
volatile int mode_7[4] = {20, 20, 10, 00}; // 筒自洁
volatile int mode_8[4] = {00, 00, 20, 00}; // 单脱水

/*******************左边9-16模式*************/
volatile int mode_9[4] = {20, 10, 20, 20};  // 轻洗
volatile int mode_10[4] = {20, 10, 20, 20}; // 混合
volatile int mode_11[4] = {20, 10, 20, 20}; // 大物
volatile int mode_12[4] = {20, 10, 20, 20}; // 棉麻
volatile int mode_13[4] = {20, 10, 20, 20}; // 羊毛
volatile int mode_14[4] = {20, 10, 20, 20}; // 羽绒
volatile int mode_15[4] = {20, 10, 20, 20}; // 童装
volatile int mode_16[4] = {20, 10, 20, 20}; // 内衣

/****************************************************/

///*******************右边1-8模式*************/

int mode1_time; // 模式1秒数
int mode2_time; // 模式2秒数
int mode3_time; // 模式3秒数
int mode4_time; // 模式4秒数
int mode5_time; // 模式5秒数
int mode6_time; // 模式6秒数
int mode7_time; // 模式7秒数
int mode8_time; // 模式8秒数

/*******************左边9-16模式*************/
int mode9_time;  // 模式9秒数
int mode10_time; // 模式10秒数
int mode11_time; // 模式11秒数
int mode12_time; // 模式12秒数
int mode13_time; // 模式13秒数
int mode14_time; // 模式14秒数
int mode15_time; // 模式15秒数
int mode16_time; // 模式16秒数

////计算各模式所需抽水、排水所需时间
void WaterTimeVa(void)
{
    /*******************右边1-8模式*************/
    mode1_time = (mode_1[0] + mode_1[1] + mode_1[2] + mode_1[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode2_time = (mode_2[0] + mode_2[1] + mode_2[2] + mode_2[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode3_time = (mode_3[0] + mode_3[1] + mode_3[2] + mode_3[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode4_time = (mode_4[0] + mode_4[1] + mode_4[2] + mode_4[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode5_time = (mode_5[0] + mode_5[1] + mode_5[2] + mode_5[3]);                                             // 计算秒数
    mode6_time = (mode_6[0] + mode_6[1] + mode_6[2] + mode_6[3]);                                             // 计算秒数
    mode7_time = (mode_7[0] + mode_7[1] + mode_7[2] + mode_7[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode8_time = (mode_8[0] + mode_8[1] + mode_8[2] + mode_8[3]);                                             // 计算秒数

    /*******************左边9-16模式*************/
    mode10_time = (mode_9[0] + mode_9[1] + mode_9[2] + mode_9[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2);     // 计算秒数
    mode11_time = (mode_10[0] + mode_10[1] + mode_10[2] + mode_10[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode12_time = (mode_11[0] + mode_11[1] + mode_11[2] + mode_11[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode13_time = (mode_12[0] + mode_12[1] + mode_12[2] + mode_12[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode14_time = (mode_13[0] + mode_13[1] + mode_13[2] + mode_13[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode15_time = (mode_14[0] + mode_14[1] + mode_14[2] + mode_14[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
    mode16_time = (mode_15[0] + mode_15[1] + mode_15[2] + mode_15[3]) + (Water_UP_Time * 2) + (Water_DW_Time * 2); // 计算秒数
}

// 继电器的io口初始化
void Relay_Config(void)
{

    // 引脚配置
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;      // 输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 输出速度
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;     // 推挽输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;       // 上拉电阻

    /**************C端口配置*************/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_8 | GPIO_Pin_11; // 引脚编号
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    /**************A端口配置*************/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // 引脚编号
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /**************E端口配置*************/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 引脚编号
    GPIO_Init(GPIOE, &GPIO_InitStructure);

    /**************G端口配置*************/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_15; // 引脚编号
    GPIO_Init(GPIOG, &GPIO_InitStructure);
}

// 天问的io口初始化
void Tianwen_Low()
{
    // 引脚配置
    GPIO_InitTypeDef GPIO_InitStructure_a;
    GPIO_InitTypeDef GPIO_InitStructure_b;
    GPIO_InitTypeDef GPIO_InitStructure_c;
    GPIO_InitTypeDef GPIO_InitStructure_g;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);

    GPIO_InitStructure_a.GPIO_Mode = GPIO_Mode_IN;     // 输入模式
    GPIO_InitStructure_a.GPIO_PuPd = GPIO_PuPd_NOPULL; // 上拉电阻

    /**************A端口配置*************/
    GPIO_InitStructure_a.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_8 | GPIO_Pin_10; // 引脚编号
    GPIO_Init(GPIOA, &GPIO_InitStructure_a);

    /**************B端口配置*************/
    GPIO_InitStructure_b.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_9; // 引脚编号
    GPIO_Init(GPIOB, &GPIO_InitStructure_b);

    /**************C端口配置*************/
    GPIO_InitStructure_c.GPIO_Pin = GPIO_Pin_9; // 引脚编号
    GPIO_Init(GPIOC, &GPIO_InitStructure_c);

    /**************G端口配置*************/
    GPIO_InitStructure_g.GPIO_Pin = GPIO_Pin_15; // 引脚编号
    GPIO_Init(GPIOG, &GPIO_InitStructure_g);
}

// 将继电器io口全部低电平
void Relay_Low(void)
{
    J_RIGHT_C1_CMD(0);

    J_RIGHT_C2_CMD(0);

    J_RIGHT_C3_CMD(0);

    J_RIGHT_E4_CMD(0);

    J_RIGHT_A5_CMD(0);

    J_RIGHT_G6_CMD(0);
}

// 将继电器io口全部高电平
void Relay_Height(void)
{
    J_RIGHT_C1_CMD(1);

    J_RIGHT_C2_CMD(1);

    J_RIGHT_C3_CMD(1);

    J_RIGHT_E4_CMD(1);

    J_RIGHT_A5_CMD(1);

    J_RIGHT_G6_CMD(1);
}

// 控制打开继电器
void Select_Relay(int cnt)
{
    switch (cnt)
    {
        // 打开右1开关（高电平输出）
    case 1:
        J_RIGHT_C1_CMD(1);
        break;

        // 打开右2开关（高电平输出）
    case 2:
        J_RIGHT_C2_CMD(1);
        break;

        // 打开右3开关（高电平输出）
    case 3:
        J_RIGHT_C3_CMD(1);
        break;

        // 打开右4开关（高电平输出）
    case 4:
        J_RIGHT_E4_CMD(1);
        break;

        // 打开右5开关（高电平输出）
    case 5:
        J_RIGHT_A5_CMD(1);
        break;

        // 打开右6开关（高电平输出）
    case 6:
        J_RIGHT_G6_CMD(1);
        break;

    default:
        Relay_Low(); // 其它数值，全部关闭开关
    }
}

/// @brief 将选择好的模式传入，即可控制马达洗衣等来洗衣
/// @param mode 选择的洗衣模式
void StartRun(int mode)
{
    TaskHandle_t TimeShow_handle = NULL; // 时间任务的句柄
    OLED_Clear();                        // 清屏

    // 选择模式
    switch (mode)
    {
    case 1:
        printf("modeq_time:    %d\n", mode1_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode1_time,   // 给任务传参
                        TimeShow_PRIORITY - 2, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode_1 is erreo\n");
        }

        printf("run:    %d\n", __LINE__);
        // 标准洗模式，包含洗涤、漂洗、甩干

        //				vTaskDelete(NULL);
        Standard();

        break;

    case 2:

        printf("modeq_time:    %d\n", mode2_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode2_time,   // 给任务传参
                        TimeShow_PRIORITY - 1, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode_2 is erreo\n");
        }

        printf("run:    %d\n", __LINE__);
        // 快速洗模式，包含洗涤、漂洗、甩干

        //				vTaskDelete(NULL);
        Speed();

        break;

    case 3:

        printf("modeq_time:    %d\n", mode3_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode3_time,   // 给任务传参
                        TimeShow_PRIORITY - 1, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode3_time is erreo\n");
        }

        printf("run:    %d\n", __LINE__);

        vTaskDelete(NULL);
        /// 洗+烘模式，包含洗涤、漂洗、甩干、烘干
        WashingDrying();

        break;

    case 4:

        printf("modeq_time:    %d\n", mode4_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode4_time,   // 给任务传参
                        TimeShow_PRIORITY - 1, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode4_time is erreo\n");
        }

        //				vTaskDelete(NULL);

        //        /// 漂+洗模式，包含洗涤、漂洗、甩干
        Rinse();

        break;

    case 5:

        printf("modeq_time:    %d\n", mode5_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode5_time,   // 给任务传参
                        TimeShow_PRIORITY - 1, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode5_time is erreo\n");
        }

        printf("run:    %d\n", __LINE__);
        /// 单烘模式，包含甩干、烘干
        //
        //				vTaskDelete(NULL);
        Drying();

        break;

    case 6:

        printf("modeq_time:    %d\n", mode6_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode6_time,   // 给任务传参
                        TimeShow_PRIORITY - 2, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode6_time is erreo\n");
        }

        printf("run:    %d\n", __LINE__);
        /// 单脱水模式，包含甩干

        //				vTaskDelete(NULL);
        Dehydration();

        break;

    case 7:

        printf("modeq_time:    %d\n", mode7_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode7_time,   // 给任务传参
                        TimeShow_PRIORITY - 1, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode7_time is erreo\n");
        }

        printf("run:    %d\n", __LINE__);

        //				vTaskDelete(NULL);
        //        /// 筒自洁模式，包含洗涤、漂洗、甩干
        SelfCleaning();

        break;

    case 8:

        printf("modeq_time:    %d\n", mode8_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode8_time,   // 给任务传参
                        TimeShow_PRIORITY - 2, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode_1 is erreo\n");
        }

        printf("run:    %d\n", __LINE__);

        //				vTaskDelete(NULL);
        //        /// 单脱水模式，包含甩干
        Dehydration();

        break;

    //******************************左边这一排的灯******************************
    case 9:

        // break;

    case 10:

        // break;

    case 11:

        // break;

    case 12:

        // break;

    case 13:

        // break;

    case 14:

        // break;

    case 15:

        // break;

    case 16:
        printf("modeq_time:    %d\n", mode1_time);
        if (xTaskCreate(Time_Show,             // 函数入口指针
                        "Time_Show",           // 任务名称
                        512,                   // 堆栈大小 128 * 32 / 8 = 512字节
                        (void *)&mode1_time,   // 给任务传参
                        TimeShow_PRIORITY - 1, // 任务优先级  数字越大则优先级越高，并且不要超过优先级最大值
                        &TimeShow_handle       // 任务的句柄，可以提供给其他API接口使用
                        )

            != pdPASS)
        {
            /* The task was created.  Use the task's handle to delete the task. */
            printf("mode_1 is erreo\n");
        }

        //				vTaskDelete(NULL);
        //        printf("run:    %d\n", __LINE__);
        //        // 标准洗模式，包含洗涤、漂洗、甩干
       Standard();

        break;

    default:
        // 标准洗模式，包含洗涤、漂洗、甩干
       Standard();

        break;
    }
}

// 时间显示的函数入口
void Time_Show(void *arg)
{
    printf("Time_Show is success!\r\n");

    // 清空全局变量数组
    memset((char *)time_arr, 0, sizeof(time_arr));

    int hour, min, sec; // 定义时分秒变量
    // char time_arr[20] = {0}; // 定义字符数组存储时间

    int tmp = *((int *)arg); // 计算秒数,从外界传入
    printf("TIMe_Show is %d\n", tmp);

    // 必须有死循环
    while (1)
    {
        // 进入临界区
        taskENTER_CRITICAL();

        hour = tmp / 3600;         // 计算小时
        tmp = (tmp - hour * 3600); // 更新余数

        min = tmp / 60;          // 计算分钟
        tmp = (tmp - hour * 60); // 更新余数

        sec = tmp % 60; // 计算描述

        sprintf((char *)time_arr, "%02d : %02d : %02d", hour, min, sec); // 将数值写入数值
                                                                         // printf( (char *)time_arr );                                                //发送给串口
        OLED_ShowString(17, 3, (u8 *)time_arr, 16);                      // 显示到OLED

        tmp--; // 将秒数减一
        if (tmp == -1)
        {
            En_Run = 0; // 运行状态改为0
            /* 如果时间到了，就自杀 */
            vTaskDelete(NULL); // 传空句柄，自杀
        }

        // 退出临界区
        taskEXIT_CRITICAL();

        vTaskDelay(1000); // 延时一秒更新
    }
}

// 水位传感器的初始化
void WaterLevel_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef ADC_InitStructure;

    // 1.打开ADC外设的接口时钟  PB1 -- ADC2_IN9
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);

    // 2.打开GPIO端口时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    // 3.配置GPIO引脚参数+初始化 注意：引脚模式为模拟模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 4.配置ADC外设的参数
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                     // 独立模式
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;                  // 预分频值  84MHZ /2 = 42MHZ
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;      // 不使用DMA
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // 两次采样的间隔时间
    ADC_CommonInit(&ADC_CommonInitStructure);

    // 5.配置ADC外设的转换精度、数据对齐
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                      // 转换精度  12bit
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;                               // 不扫描
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                         // 不连续转换
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // 不使用外部触发源
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                      // 数据对齐  右对齐
    ADC_InitStructure.ADC_NbrOfConversion = 1;                                  // 转换序号
    ADC_Init(ADC2, &ADC_InitStructure);

    // 6.配置ADC的规则通道  总转换时间 = 3 + 12 = 15周期
    ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 1, ADC_SampleTime_3Cycles);

    // 7.使能ADC
    ADC_Cmd(ADC2, ENABLE);
}

// 抽水的函数
void Water_Put(void)
{
    // 打开水位继电器开关，时刻检测水位
    J_RIGHT_C1_CMD(1);

    // 打开抽水马达继电器开关，开始抽水
    J_RIGHT_C2_CMD(1);

    // 进入循环判断
    int tmp = 0;  // 临时水位值
    int time = 0; // 当前用时值
    OLED_Clear(); // 清屏

    while (1)
    {
        // OLED_Clear(); 		   //清屏

        // 开启ADC转换
        ADC_SoftwareStartConv(ADC2);

        // 等待转换完成 EOC标志
        while (ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET)
            ;

        // 读取ADC转换结果  12bit精度 value 0 ~ 4095
        tmp = ADC_GetConversionValue(ADC2);

        // OLED_ShowNum(0,0,tmp,4,16);
        printf("water_valae: %d\n", tmp);

        // 消抖处理
        if (tmp >= 3400)
        {
            delay_ms(500);
            delay_ms(500);
        }

        // 如果水位级别到达37，或者超过了40s，那么关闭马达继电器、水位继电器
        if (tmp >= 3900 || time >= Water_UP_Time)
        {
            J_RIGHT_C2_CMD(0); // 关闭马达
            //		   J_RIGHT_C1_CMD(0) ;     //关闭水位
            break;
        }

        time++;
        // OLED_ShowNum(0,3,time,3,16);
        printf("time: %d\n", time);
        delay_ms(500); // 每隔100ms检测一次，也就是1秒10次
        delay_ms(500); // 每隔100ms检测一次，也就是1秒10次
    }
}

// 排水的函数
void Water_Down(void)
{
    // 打开水位继电器开关，时刻检测水位
    J_RIGHT_C1_CMD(1);

    // 打开排水马达继电器开关，开始抽水
    J_RIGHT_C3_CMD(3);

    // 进入循环判断
    int tmp = 0;  // 临时水位值
    int time = 0; // 当前用时值

    // OLED_Clear(); 		   //清屏

    while (1)
    {
        // OLED_Clear(); 		   //清屏

        // 开启ADC转换
        ADC_SoftwareStartConv(ADC2);

        // 等待转换完成 EOC标志
        while (ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET)
            ;

        // 读取ADC转换结果  12bit精度 value 0 ~ 4095
        tmp = ADC_GetConversionValue(ADC2);

        // OLED_ShowNum(0,0,tmp,4,16);
        printf("water_valae: %d\n", tmp);

        // 消抖处理
        if (tmp <= 100)
        {
            while (1)
            {
                ADC_SoftwareStartConv(ADC2);

                // 等待转换完成 EOC标志
                while (ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET)

                    // 读取ADC转换结果  12bit精度 value 0 ~ 4095
                    tmp = ADC_GetConversionValue(ADC2);
                // OLED_ShowNum(0,0,tmp,4,16);
                printf("water_valae: %d\n", tmp);

                printf("time: %d\n", time);

                if (tmp >= 2000 || time >= Water_DW_Time)
                {
                    break;
                }

                time++;
                // 延时500ms
                delay_ms(500);
                delay_ms(500);
            }
        }

        // 如果水位级别到达37，或者超过了40s，那么关闭马达继电器、水位继电器
        if (tmp <= 2700 || time >= Water_DW_Time)
        {
            J_RIGHT_C3_CMD(0); // 关闭马达
            //		   J_RIGHT_C1_CMD(0) ;     //关闭水位
            break;
        }

        time++;
        // OLED_ShowNum(0,0,tmp,4,16);
        printf("time: %d\n", time);
        delay_ms(500); // 每隔100ms检测一次，也就是1秒10次
        delay_ms(500); // 每隔100ms检测一次，也就是1秒10次
    }
}

// 蜂鸣器的初始化
void Beep_Config(void)
{

    GPIO_InitTypeDef GPIO_InitStructure;

    // 2.打开GPIO端口时钟  PF8
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

    // 3.配置GPIO引脚并初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;          // 引脚编号
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;      // 复用模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 输出速率
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;     // 推挽输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;       // 上拉电阻
    GPIO_Init(GPIOF, &GPIO_InitStructure);
}

/// @brief 标准洗模式，包含洗涤、漂洗、甩干、烘干
void Standard(void)
{
    // 1.将倒计时显示到OLED屏幕（）
    // OLED_Clear(); 		   //清屏
    // RUN_CMD(En_Run); // 发送运行标志

    // 2.开始上水
    Water_Put(); // 抽水功能

    // 3.洗涤时间
    J_RIGHT_A5_CMD(1); // 启动电机马达

    int a = mode_1[0];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 4.排水
    J_RIGHT_A5_CMD(0); // 关闭电机马达
    Water_Down();      // 排水功能

    // 4.漂洗时间
    Water_Put(); // 抽水功能
    a = mode_1[1];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 5.排水
    Water_Down(); // 排水功能

    // 6.甩干时间
    J_RIGHT_C1_CMD(0); // 关闭水位模块
    J_RIGHT_A5_CMD(1); // 启动电机马达
    a = mode_1[2];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // OLED_ShowNum(0,3,888,3,16);
    printf("strta HOt 888\n");

    // 7烘干
    J_RIGHT_E4_CMD(1); // 打开马达
    J_RIGHT_A5_CMD(1); // 打开风扇
    J_RIGHT_G6_CMD(1); // 打开电热片

    a = mode_1[3];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    J_RIGHT_E4_CMD(0); // 关闭风扇开关
    J_RIGHT_G6_CMD(0); // 关闭电热片开关
    J_RIGHT_A5_CMD(0); // 关闭马达转动

    // 7.蜂鸣器叫

    BeepExalrm();

    // 8.运行结束
    En_Run = 0;      // 结束运行标识
    RUN_CMD(En_Run); // 发送运行标志
    BLOCK_CMD(1);    // 开锁5s钟
    a = 8;
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁
}

/// @brief 快速洗模式，包含洗涤、漂洗、甩干
void Speed(void)
{
    // 1.将倒计时显示到OLED屏幕（创建任务）
    // OLED_Clear();    // 清屏
    //  En_Run = 1;      // 开始运行标志
    //  RUN_CMD(En_Run); // 发送运行标志

    // 2.开始上水
    Water_Put(); // 抽水功能

    // 3.洗涤时间
    J_RIGHT_A5_CMD(1); // 启动电机马达

    int a = mode_2[0];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 4.排水
    J_RIGHT_A5_CMD(0); // 关闭电机马达
    Water_Down();      // 排水功能

    // 4.漂洗时间
    Water_Put(); // 抽水功能
    a = mode_2[1];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 5.排水
    Water_Down(); // 排水功能

    // 6.甩干时间
    J_RIGHT_C1_CMD(0); // 关闭水位模块
    J_RIGHT_A5_CMD(1); // 启动电机马达
    a = mode_2[2];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0);      // 关锁
    J_RIGHT_A5_CMD(0); // 关闭电机马达

    // 7.蜂鸣器叫
    BeepExalrm();

    // 8.运行结束
    En_Run = 0;      // 结束运行标识
    RUN_CMD(En_Run); // 发送运行标志
    BLOCK_CMD(1);    // 开锁5s钟
    a = 8;
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁
}

/// @brief 洗+烘模式，包含洗涤、漂洗、甩干、烘干
void WashingDrying(void)
{
    // 1.将倒计时显示到OLED屏幕（创建任务）
    // OLED_Clear();    // 清屏
    //  En_Run = 1;      // 开始运行标志
    //  RUN_CMD(En_Run); // 发送运行标志

    // 2.开始上水
    Water_Put(); // 抽水功能

    // 3.洗涤时间
    J_RIGHT_A5_CMD(1); // 启动电机马达

    int a = mode_3[0];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 4.排水
    J_RIGHT_A5_CMD(0); // 关闭电机马达
    Water_Down();      // 排水功能

    // 4.漂洗时间
    Water_Put(); // 抽水功能
    a = mode_3[1];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 5.排水
    Water_Down(); // 排水功能

    // 6.甩干时间
    J_RIGHT_C1_CMD(0); // 关闭水位模块
    J_RIGHT_A5_CMD(1); // 启动电机马达
    a = mode_3[2];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0);      // 关锁
    J_RIGHT_A5_CMD(0); // 关闭电机马达

    // 7烘干
    J_RIGHT_E4_CMD(1); // 打开马达
    J_RIGHT_A5_CMD(1); // 打开风扇
    J_RIGHT_G6_CMD(1); // 打开电热片

    a = mode_3[3];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    J_RIGHT_E4_CMD(0); // 关闭风扇开关
    J_RIGHT_G6_CMD(0); // 关闭电热片开关
    J_RIGHT_A5_CMD(0); // 关闭马达转动

    // 8.蜂鸣器叫
    BeepExalrm();

    // 9.运行结束
    En_Run = 0;      // 结束运行标识
    RUN_CMD(En_Run); // 发送运行标志
    BLOCK_CMD(1);    // 开锁5s钟
    a = 8;
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁
}

/// @brief 漂+洗模式，包含洗涤、漂洗、甩干
void Rinse(void)
{
    // 1.将倒计时显示到OLED屏幕（创建任务）
    // OLED_Clear();    // 清屏
    //  En_Run = 1;      // 开始运行标志
    //  RUN_CMD(En_Run); // 发送运行标志

    // 2.开始上水
    Water_Put(); // 抽水功能

    // 3.洗涤时间
    J_RIGHT_A5_CMD(1); // 启动电机马达

    int a = mode_4[0];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 4.排水
    J_RIGHT_A5_CMD(0); // 关闭电机马达
    Water_Down();      // 排水功能

    // 5.漂洗时间
    Water_Put(); // 抽水功能
    a = mode_4[1];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 6.排水
    Water_Down(); // 排水功能

    // 7.甩干时间
    J_RIGHT_C1_CMD(0); // 关闭水位模块
    J_RIGHT_A5_CMD(1); // 启动电机马达
    a = mode_4[2];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0);      // 关锁
    J_RIGHT_A5_CMD(0); // 关闭电机马达

    // 8.蜂鸣器叫
    BeepExalrm();

    // 9.运行结束
    En_Run = 0;      // 结束运行标识
    RUN_CMD(En_Run); // 发送运行标志
    BLOCK_CMD(1);    // 开锁5s钟
    a = 8;
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁
}

/// @brief 单烘模式，包含甩干、烘干
void Drying(void)
{
    // 1.将倒计时显示到OLED屏幕（创建任务）
    // OLED_Clear();    // 清屏
    //  En_Run = 1;      // 开始运行标志
    //  RUN_CMD(En_Run); // 发送运行标志

    // 2.甩干时间
    J_RIGHT_C1_CMD(0); // 关闭水位模块
    J_RIGHT_A5_CMD(1); // 启动电机马达
    int a = mode_5[2];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0);      // 关锁
    J_RIGHT_A5_CMD(0); // 关闭电机马达

    // 3烘干
    J_RIGHT_E4_CMD(1); // 打开马达
    J_RIGHT_A5_CMD(1); // 打开风扇
    J_RIGHT_G6_CMD(1); // 打开电热片

    a = mode_5[3];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    J_RIGHT_E4_CMD(0); // 关闭风扇开关
    J_RIGHT_G6_CMD(0); // 关闭电热片开关
    J_RIGHT_A5_CMD(0); // 关闭马达转动

    // 4.蜂鸣器叫
    BeepExalrm();

    // 5.运行结束
    En_Run = 0;      // 结束运行标识
    RUN_CMD(En_Run); // 发送运行标志
    BLOCK_CMD(1);    // 开锁5s钟
    a = 5;
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁
}

/// @brief 单脱水模式，包含甩干
void Dehydration(void)
{
    // 1.将倒计时显示到OLED屏幕（创建任务）
    // OLED_Clear();    // 清屏
    //  En_Run = 1;      // 开始运行标志
    //  RUN_CMD(En_Run); // 发送运行标志

    // 2.甩干时间
    J_RIGHT_C1_CMD(0); // 关闭水位模块
    J_RIGHT_A5_CMD(1); // 启动电机马达
    int a = mode_6[2];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0);      // 关锁
    J_RIGHT_A5_CMD(0); // 关闭电机马达

    // 3.蜂鸣器叫
    BeepExalrm();

    // 4.运行结束
    En_Run = 0;      // 结束运行标识
    RUN_CMD(En_Run); // 发送运行标志
    BLOCK_CMD(1);    // 开锁5s钟
    a = 8;
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁
}

/// @brief 筒自洁模式，包含洗涤、漂洗、甩干
void SelfCleaning(void)
{
    // 1.将倒计时显示到OLED屏幕（创建任务）
    // OLED_Clear();    // 清屏
    //  En_Run = 1;      // 开始运行标志
    //  RUN_CMD(En_Run); // 发送运行标志

    // 2.开始上水
    Water_Put(); // 抽水功能

    // 3.洗涤时间
    J_RIGHT_A5_CMD(1); // 启动电机马达

    int a = mode_7[0];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 4.排水
    J_RIGHT_A5_CMD(0); // 关闭电机马达
    Water_Down();      // 排水功能

    // 4.漂洗时间
    Water_Put(); // 抽水功能
    a = mode_7[1];
    // 延时指定时间
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁

    // 5.排水
    Water_Down(); // 排水功能

    // 6.甩干时间
    J_RIGHT_C1_CMD(0); // 关闭水位模块
    J_RIGHT_A5_CMD(1); // 启动电机马达
    a = mode_7[2];
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0);      // 关锁
    J_RIGHT_A5_CMD(0); // 关闭电机马达

    // 7.蜂鸣器叫
    BeepExalrm();

    // 8.运行结束
    En_Run = 0;      // 结束运行标识
    RUN_CMD(En_Run); // 发送运行标志
    BLOCK_CMD(1);    // 开锁5s钟
    a = 8;
    while (a--)
    {
        delay_ms(500);
        delay_ms(500);
    }
    BLOCK_CMD(0); // 关锁
}

// 蜂鸣器响的函数
void BeepExalrm(void)
{
    printf("ok ok ok go go go !\n");
    int beep = 5;
    while (beep--)
    {
        if (beep % 2 == 0)
        {
            BEEP_F8_CMD(0);
        }
        else
        {
            BEEP_F8_CMD(1);
        }
        delay_ms(500);
        delay_ms(500);
    }
}
